home *** CD-ROM | disk | FTP | other *** search
/ Animation / Animation Vol.1 (Profi ROM)(1994).iso / source.zip / 3DS2POV.C next >
C/C++ Source or Header  |  1993-10-02  |  66KB  |  2,776 lines

  1. /*
  2.       3DS2POV.C  Copyright (c) 1993 Steve Anger and Jeff Bowermaster
  3.  
  4.       Reads a 3D Studio .3DS file and writes a POV-Ray, Vivid, or
  5.       Polyray scene file.
  6.  
  7.       Version 1.8 Written Oct/93
  8.  
  9.       Compiled with MSDOS GNU C++ 2.4.1
  10. */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <math.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "vect.h"
  18. #include "rayopt.h"
  19.  
  20. #ifdef __TURBOC__
  21. #include <alloc.h>
  22. extern unsigned _stklen = 16384;
  23. #endif
  24.  
  25.  
  26. #define FALSE 0
  27. #define TRUE  1
  28.  
  29. /* Internal bounding modes */
  30. #define OFF  0
  31. #define ON   1
  32. #define AUTO 2
  33.  
  34. #define MAX_LIB  10
  35. #define ASPECT   1.333
  36.  
  37. /* Output formats */
  38. #define POV10    0
  39. #define POV20    1
  40. #define VIVID    2
  41. #define POLYRAY  3
  42. #define RAW      99
  43.  
  44. #define DEG(x) ((180.0/M_PI)*(x))
  45. #define RAD(x) ((M_PI/180.0)*(x))
  46.  
  47. #ifndef M_PI
  48. #define M_PI (3.1415926535)
  49. #endif
  50.  
  51. #ifndef MAXFLOAT
  52. #define MAXFLOAT (1e37)
  53. #endif
  54.  
  55. /* A generic list type */
  56. #define LIST_INSERT(root, node) list_insert ((List **)&root, (List *)node)
  57. #define LIST_FIND(root, name)   list_find   ((List **)&root, name)
  58. #define LIST_DELETE(root, node) list_delete ((List **)&root, (List *)node)
  59. #define LIST_KILL(root)         list_kill   ((List **)&root)
  60.  
  61. #define LIST_FIELDS  \
  62.     char name[80];   \
  63.     void *next;
  64.  
  65.  
  66. typedef unsigned char  byte;
  67. typedef unsigned short word;
  68. typedef unsigned long  dword;
  69.  
  70. typedef struct {
  71.     LIST_FIELDS
  72. } List;
  73.  
  74.  
  75. typedef struct {
  76.     int a, b, c;
  77. } Face;
  78.  
  79.  
  80. typedef struct {
  81.     float red, green, blue;
  82. } Colour;
  83.  
  84.  
  85. /* Transformation command */
  86. typedef struct {
  87.     LIST_FIELDS
  88.  
  89.     Matrix matrix;
  90. } Transform;
  91.  
  92.  
  93. /* Morph command */
  94. typedef struct {
  95.     LIST_FIELDS
  96.  
  97.     int    count;          /* Number of objects in morph */
  98.     char   names[4][80];   /* Name of n'th object in average */
  99.     float  weight[4];      /* Weight applied to n'th object */
  100.  
  101.     Matrix matrix;
  102. } Morph;
  103.  
  104.  
  105. /* Omni light command */
  106. typedef struct {
  107.     LIST_FIELDS
  108.  
  109.     Vector pos;            /* Light position */
  110.     Colour col;            /* Light colour */
  111. } OmniLight;
  112.  
  113.  
  114. /* Spotlight command */
  115. typedef struct {
  116.     LIST_FIELDS
  117.  
  118.     Vector pos;            /* Spotlight position */
  119.     Vector target;         /* Spotlight target location */
  120.     Colour col;            /* Spotlight colour */
  121.     float  hotspot;        /* Hotspot angle (degrees) */
  122.     float  falloff;        /* Falloff angle (degrees) */
  123.     int    shadow_flag;    /* Shadow flag (not used) */
  124. } Spotlight;
  125.  
  126.  
  127. /* Camera command */
  128. typedef struct {
  129.     LIST_FIELDS
  130.  
  131.     Vector pos;            /* Camera location */
  132.     Vector target;         /* Camera target */
  133.     float  bank;           /* Banking angle (degrees) */
  134.     float  lens;           /* Camera lens size (mm) */
  135. } Camera;
  136.  
  137.  
  138. /* Material list */
  139. typedef struct {
  140.     LIST_FIELDS
  141.  
  142.     int  external;         /* Externally defined material? */
  143. } Material;
  144.  
  145.  
  146. /* Object summary */
  147. typedef struct {
  148.     LIST_FIELDS
  149.  
  150.     Vector center;         /* Min value of object extents */
  151.     Vector lengths;        /* Max value of object extents */
  152. } Summary;
  153.  
  154.  
  155. /* Material property */
  156. typedef struct {
  157.     LIST_FIELDS
  158.  
  159.     Colour ambient;
  160.     Colour diffuse;
  161.     Colour specular;
  162.     float  shininess;
  163.     float  transparency;
  164.     float  reflection;
  165.     int    self_illum;
  166.     char   tex_map[40];
  167.     float  tex_strength;
  168.     char   bump_map[40];
  169.     float  bump_strength;
  170. } MatProp;
  171.  
  172.  
  173. /* Default material property */
  174. MatProp DefaultMaterial = { "Default", NULL, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0},
  175.                  {1.0, 1.0, 1.0}, 70.0, 0.0, 0.0, FALSE };
  176.  
  177. /* A mesh object */
  178. typedef struct {
  179.     LIST_FIELDS
  180.  
  181.     int  vertices;         /* Number of vertices */
  182.     Vector *vertex;        /* List of object vertices */
  183.  
  184.     int  faces;            /* Number of faces */
  185.     Face *face;            /* List of object faces */
  186.     Material **mtl;        /* Materials for each face */
  187.  
  188.     Matrix matrix;         /* Local mesh matrix */
  189.     Matrix invmatrix;
  190.     Vector center;         /* Center of object */
  191.     Vector lengths;        /* Dimensions of object */
  192.  
  193.     int hidden;            /* Hidden flag */
  194.     int shadow;            /* Shadow flag */
  195. } Mesh;
  196.  
  197.  
  198. typedef struct {
  199.     dword start;
  200.     dword end;
  201.     dword length;
  202.     word  tag;
  203. } Chunk;
  204.  
  205.  
  206. typedef struct {
  207.     byte red;
  208.     byte green;
  209.     byte blue;
  210. } Colour_24;
  211.  
  212.  
  213. Colour Black = {0.0, 0.0, 0.0};
  214.  
  215. OmniLight *omni_list  = NULL;
  216. Spotlight *spot_list  = NULL;
  217. Camera    *cam_list   = NULL;
  218. Mesh      *mesh_list  = NULL;
  219. Transform *trans_list = NULL;
  220. Morph     *morph_list = NULL;
  221. Material  *mtl_list   = NULL;
  222. List      *excl_list  = NULL;
  223. List      *box_list   = NULL;
  224. MatProp   *mprop_list = NULL;
  225. Summary   *summary    = NULL;
  226.  
  227.  
  228. FILE   *in;
  229. FILE   *out;
  230. char   inname[80];
  231. char   outname[80];
  232. char   vuename[80];
  233. char   obj_name[80] = "";
  234. Colour fog_colour = {0.0, 0.0, 0.0};
  235. Colour col        = {0.0, 0.0, 0.0};
  236. Colour global_amb = {0.1, 0.1, 0.1};
  237. Vector pos        = {0.0, 0.0, 0.0};
  238. Vector target     = {0.0, 0.0, 0.0};
  239. float  fog_distance = 0.0;
  240. float  hotspot = -1;
  241. float  falloff = -1;
  242. Mesh   *mesh = NULL;
  243. int    frame = -1;
  244. char   libname[MAX_LIB][80];
  245. float  smooth = 60.0;
  246. int    bound = 0;
  247. int    verbose = 0;
  248. int    format = POV20;
  249. int    internal_bounding = AUTO;
  250. int    box_all = FALSE;
  251. int    cameras = 0;
  252. int    libs = 0;
  253. float  vue_version = 1.0;
  254. Matrix *ani_matrix = NULL;
  255.  
  256.  
  257. void process_args (int argc, char *argv[]);
  258. void parse_option (char *option);
  259. void list_insert (List **root, List *new_node);
  260. void *list_find (List **root, char *name);
  261. void list_delete (List **root, List *node);
  262. void list_kill (List **root);
  263. Material *update_materials (char *new_material, int ext);
  264. MatProp *create_mprop (void);
  265. void read_library (char *fname);
  266. void write_intro (FILE *f);
  267. void write_summary (FILE *f);
  268. void write_bgsolid (FILE *f, Colour col);
  269. void write_light (FILE *f, char *name, Vector pos, Colour col);
  270. void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
  271.      float hotspot, float falloff);
  272. void write_fog (FILE *f, Colour col, float dist);
  273. void write_camera (FILE *f, char *name, Vector pos, Vector target, float lens,
  274.      float bank);
  275. void write_material (FILE *f, char *mat);
  276. void write_pov10_material (FILE *f, MatProp *m);
  277. void write_pov20_material (FILE *f, MatProp *m);
  278. void write_vivid_material (FILE *f, MatProp *m);
  279. void write_polyray_material (FILE *f, MatProp *m);
  280. void write_mesh (FILE *f, Mesh *mesh);
  281. Transform *parse_transform (char *string);
  282. Morph *parse_morph (char *string);
  283. OmniLight *parse_omnilight (char *string);
  284. Spotlight *parse_spotlight (char *string);
  285. Camera *parse_camera (char *string);
  286. void read_frame (char *filename, int frame_no);
  287. void find_frame (FILE *f, int frame_no);
  288. void save_animation (void);
  289. Mesh *create_mesh (char *name, int vertices, int faces);
  290. Mesh *copy_mesh (Mesh *mesh);
  291. void free_mesh_data (Mesh *mesh);
  292. void update_limits (Mesh *mesh);
  293. char *before (char *str, char *target);
  294. char *after (char *str, char *target);
  295. char *between (char *str, char *target1, char *target2);
  296. char *parse_string (char *str);
  297. char upcase (char c);
  298. float colour_intens (Colour *colour);
  299. void parse_file (void);
  300. void parse_3ds (Chunk *mainchunk);
  301. void parse_mdata (Chunk *mainchunk);
  302. void parse_fog (Chunk *mainchunk);
  303. void parse_fog_bgnd (void);
  304. void parse_mat_entry (Chunk *mainchunk);
  305. char *parse_mapname (Chunk *mainchunk);
  306. void parse_named_object (Chunk *mainchunk);
  307. void parse_n_tri_object (Chunk *mainchunk);
  308. void parse_point_array (void);
  309. void parse_face_array (Chunk *mainchunk);
  310. void parse_msh_mat_group (void);
  311. void parse_smooth_group (void);
  312. void parse_mesh_matrix (void);
  313. void parse_n_direct_light (Chunk *mainchunk);
  314. void parse_dl_spotlight (void);
  315. void parse_n_camera (void);
  316. void parse_colour (Colour *colour);
  317. void parse_colour_f (Colour *colour);
  318. void parse_colour_24 (Colour_24 *colour);
  319. float parse_percentage (void);
  320. short parse_int_percentage (void);
  321. float parse_float_percentage (void);
  322. void start_chunk (Chunk *chunk);
  323. void end_chunk (Chunk *chunk);
  324. byte read_byte (void);
  325. word read_word (void);
  326. dword read_dword (void);
  327. float read_float (void);
  328. void read_point (Vector v);
  329. char *read_string (void);
  330. float findfov (float lens);
  331.  
  332.  
  333. int main (int argc, char *argv[])
  334. {
  335.     Material *m;
  336.     int i;
  337.  
  338.     process_args (argc, argv);
  339.  
  340.     if (format != RAW) {
  341.     opt_set_format (format);
  342.     opt_set_dec (4);
  343.     opt_set_bound (bound);
  344.     opt_set_smooth (smooth);
  345.     opt_set_quiet (!verbose);
  346.     opt_set_fname (outname, "");
  347.     }
  348.  
  349.     if ((in = fopen (inname, "rb")) == NULL) {
  350.     printf ("Cannot open input file %s!\n", inname);
  351.     exit (1);
  352.     }
  353.  
  354.     if ((out = fopen (outname, "w")) == NULL) {
  355.     printf ("Cannot open output file %s!\n", outname);
  356.     exit (1);
  357.     }
  358.  
  359.     /* Load the names of pre-defined materials */
  360.     for (i = 0; i < MAX_LIB; i++) {
  361.     if (strlen(libname[i]) > 0)
  362.         read_library (libname[i]);
  363.     }
  364.  
  365.     /* Load the instructions for the current frame */
  366.     if (strlen(vuename) > 0)
  367.     read_frame (vuename, frame);
  368.  
  369.     printf("Output to: %s\n", outname);
  370.  
  371.     if (frame >= 0)
  372.     printf ("Generating frame #%d\n", frame);
  373.  
  374.     printf("\nPlease wait; Processing...\n");
  375.  
  376.     write_intro(out);
  377.  
  378.     parse_file();
  379.  
  380.     fclose(in);
  381.  
  382.     for (m = mtl_list; m != NULL; m = m->next) {
  383.     if (!m->external)
  384.         write_material (out, m->name);
  385.     }
  386.  
  387.     fclose (out);
  388.  
  389.     if (frame >= 0)
  390.     save_animation();
  391.  
  392.     if (format != RAW) {
  393.         out = fopen (outname, "a");
  394.         write_summary (out);
  395.         fclose (out);
  396.  
  397.     opt_finish();
  398.     }
  399.  
  400.     LIST_KILL (omni_list);
  401.     LIST_KILL (spot_list);
  402.     LIST_KILL (cam_list);
  403.     LIST_KILL (mesh_list);
  404.     LIST_KILL (trans_list);
  405.     LIST_KILL (morph_list);
  406.     LIST_KILL (mtl_list);
  407.     LIST_KILL (excl_list);
  408.     LIST_KILL (box_list);
  409.     LIST_KILL (mprop_list);
  410.     LIST_KILL (summary);
  411.  
  412.     return 0;
  413. }
  414.  
  415.  
  416. /* Handle the command line args */
  417. void process_args (int argc, char *argv[])
  418. {
  419.     int i;
  420.     char *env_opt, *option;
  421.  
  422.     printf("\n\nAutodesk 3D Studio to Raytracer file Translator. Oct/93\n");
  423.     printf("Version 1.8 Copyright (c) 1993 Steve Anger and Jeff Bowermaster\n");
  424. #ifdef __GNUC__
  425.     printf ("32 bit version. DOS extender Copyright (c) 1991 DJ Delorie\n");
  426. #endif
  427.     printf ("\n");
  428.  
  429.     if (argc < 2) {
  430.     printf ("Usage: 3ds2pov inputfile[.3ds] [outputfile] [options]\n\n");
  431.     printf ("Options: -snnn        - Smooth triangles with angles < nnn\n");
  432.     printf ("         -l<filename> - Specifies 3DS texture library\n");
  433.     printf ("         -a<filename> - Use animation information in specified file\n");
  434.     printf ("         -fnnn        - Generate frame nnn of animation\n");
  435.     printf ("         -x<object>   - Exclude this object from conversion\n");
  436.     printf ("         -b<object>   - Convert this object as a box\n");
  437.     printf ("         +i, -i       - Turn internal bounding on or off\n");
  438.     printf ("         +v, -v       - Turn verbose status messages on or off\n");
  439.     printf ("         -op          - Output to POV-Ray 2.0 format (default)\n");
  440.     printf ("         -op1         - Output to POV-Ray 1.0 format\n");
  441.     printf ("         -ov          - Output to Vivid format\n");
  442.     printf ("         -ol          - Output to poLyray format\n");
  443.     printf ("         -or          - Output to RAW triangle format\n\n");
  444.     printf ("ex. 3ds2pov birdshow +v -l3ds.inc\n\n");
  445.     exit(1);
  446.     }
  447.  
  448.     strcpy (inname, "");
  449.     strcpy (outname, "");
  450.     strcpy (vuename, "");
  451.  
  452.     for (i = 0; i < MAX_LIB; i++)
  453.     strcpy (libname[i], "");
  454.  
  455.     frame = -1;
  456.     smooth = 70.0;
  457.     bound = 0;
  458.     verbose = 0;
  459.     format = POV20;
  460.     internal_bounding = AUTO;
  461.     box_all = FALSE;
  462.     libs = 0;
  463.  
  464.     /* Parse the enviroment string options */
  465.     env_opt = getenv ("3DS2POV");
  466.  
  467.     if (env_opt != NULL) {
  468.     option = parse_string (env_opt);
  469.  
  470.     while (strlen(option) > 0) {
  471.         parse_option (option);
  472.         option = parse_string (NULL);
  473.     }
  474.     }
  475.  
  476.     /* Parse the command line options */
  477.     for (i = 1; i < argc; i++)
  478.     parse_option (argv[i]);
  479.  
  480.     if (strlen(inname) == 0)
  481.     abortmsg ("No input file specified", 1);
  482.  
  483.     if (strlen(outname) == 0) {
  484.     strcpy (outname, inname);
  485.  
  486.     switch (format) {
  487.         case POV10:
  488.         case POV20:   add_ext (outname, "pov", 1); break;
  489.         case VIVID:   add_ext (outname, "v",   1); break;
  490.         case POLYRAY: add_ext (outname, "pi",  1); break;
  491.         case RAW:     add_ext (outname, "raw", 1); break;
  492.     }
  493.     }
  494.     else {
  495.     switch (format) {
  496.         case POV10:
  497.         case POV20:   add_ext (outname, "pov", 0); break;
  498.         case VIVID:   add_ext (outname, "v",   0); break;
  499.         case POLYRAY: add_ext (outname, "pi",  0); break;
  500.         case RAW:     add_ext (outname, "raw", 0); break;
  501.     }
  502.     }
  503.  
  504.     switch (internal_bounding) {
  505.     case OFF:  bound = 2; break;
  506.     case ON:   bound = 0; break;
  507.     case AUTO: bound = (format == POV10) ? 0 : 2; break;
  508.     }
  509.  
  510.     if ((strlen(vuename) > 0) != (frame >= 0))
  511.     abortmsg ("The -a and -f parameters must be used together", 1);
  512. }
  513.  
  514.  
  515. void parse_option (char *option)
  516. {
  517.     List *excl, *box;
  518.     char name[80];
  519.  
  520.     if (option[0] == '-' || option[0] == '+') {
  521.     switch (upcase(option[1])) {
  522.         case 'A': strcpy (vuename, &option[2]);
  523.               break;
  524.  
  525.         case 'B': strcpy (name, parse_string (&option[2]));
  526.               if (strlen(name) == 0)
  527.               box_all = TRUE;
  528.               else {
  529.               cleanup_name (name);
  530.  
  531.               box = malloc (sizeof (*box));
  532.               strcpy (box->name, name);
  533.  
  534.               LIST_INSERT (box_list, box);
  535.               }
  536.               break;
  537.  
  538.         case 'F': if (option[2] != '\0')
  539.               frame = atoi (&option[2]);
  540.               break;
  541.  
  542.         case 'I': if (option[0] == '-')
  543.               internal_bounding = OFF;
  544.               else
  545.               internal_bounding = ON;
  546.               break;
  547.  
  548.         case 'L': if (libs == MAX_LIB)
  549.               abortmsg ("Too many libraries specified", 1);
  550.  
  551.               strcpy (libname[libs++], &option[2]);
  552.               break;
  553.  
  554.         case 'O': switch (upcase(option[2])) {
  555.               case 'P': if (option[3] == '1')
  556.                     format = POV10;
  557.                     else
  558.                     format = POV20;
  559.                     break;
  560.  
  561.               case 'V': format = VIVID;
  562.                     break;
  563.  
  564.               case 'L': format = POLYRAY;
  565.                     break;
  566.  
  567.               case 'R': format = RAW;
  568.                     break;
  569.  
  570.               default:  printf ("Invalid output format %s specified\n", option);
  571.                     exit(1);
  572.               }
  573.               break;
  574.  
  575.         case 'S': if (option[2] != '\0')
  576.               smooth = atof (&option[2]);
  577.               break;
  578.  
  579.         case 'U': printf ("Warning: -u parameter no long has any effect\n");
  580.               printf ("         use +i or -i instead.\n");
  581.               break;
  582.  
  583.         case 'V': if (option[0] == '-')
  584.               verbose = 0;
  585.               else
  586.               verbose = 1;
  587.               break;
  588.  
  589.         case 'X': strcpy (name, parse_string (&option[2]));
  590.               cleanup_name (name);
  591.  
  592.               excl = malloc (sizeof (*excl));
  593.               strcpy (excl->name, name);
  594.  
  595.               LIST_INSERT (excl_list, excl);
  596.               break;
  597.  
  598.         default : printf ("\nInvalid option %s specified\n", option);
  599.               exit (1);
  600.     }
  601.     }
  602.     else if (strlen (inname) == 0) {
  603.     strcpy (inname, option);
  604.     add_ext (inname, "3ds", 0);
  605.     }
  606.     else if (strlen (outname) == 0)
  607.     strcpy (outname, option);
  608.     else
  609.     abortmsg ("Too many file names specified.\n", 1);
  610. }
  611.  
  612.  
  613. /* Insert a new node into the list */
  614. void list_insert (List **root, List *new_node)
  615. {
  616.     new_node->next = *root;
  617.  
  618.     *root = new_node;
  619. }
  620.  
  621.  
  622. /* Find the node with the specified name */
  623. void *list_find (List **root, char *name)
  624. {
  625.     List *p;
  626.  
  627.     for (p = *root; p != NULL; p = p->next) {
  628.     if (strcmp (p->name, name) == 0)
  629.         break;
  630.     }
  631.  
  632.     return (void *)p;
  633. }
  634.  
  635.  
  636. /* Delete the indicated node from the list */
  637. void list_delete (List **root, List *node)
  638. {
  639.     List *prev;
  640.  
  641.     prev = *root;
  642.     while (prev != NULL && prev->next != node)
  643.     prev = prev->next;
  644.  
  645.     if (prev == NULL)
  646.     *root = node->next;
  647.     else
  648.     prev->next = node->next;
  649.  
  650.     free (node);
  651. }
  652.  
  653.  
  654. /* Delete the entire list */
  655. void list_kill (List **root)
  656. {
  657.     List *temp;
  658.  
  659.     while (*root != NULL) {
  660.     temp = *root;
  661.     *root = (*root)->next;
  662.     free (temp);
  663.     }
  664. }
  665.  
  666.  
  667. /* Add a new material to the material list */
  668. Material *update_materials (char *new_material, int ext)
  669. {
  670.     Material *p;
  671.  
  672.     p = LIST_FIND (mtl_list, new_material);
  673.  
  674.     if (p == NULL) {
  675.     p = malloc (sizeof (*p));
  676.  
  677.     if (p == NULL)
  678.         abortmsg ("Out of memory adding material", 1);
  679.  
  680.     strcpy (p->name, new_material);
  681.     p->external = ext;
  682.  
  683.     LIST_INSERT (mtl_list, p);
  684.     }
  685.  
  686.     return p;
  687. }
  688.  
  689.  
  690. MatProp *create_mprop()
  691. {
  692.     MatProp *new_mprop;
  693.  
  694.     new_mprop = malloc (sizeof(*new_mprop));
  695.     if (new_mprop == NULL)
  696.     abortmsg ("Out of memory adding material", 1);
  697.  
  698.     strcpy (new_mprop->name, "");
  699.     new_mprop->ambient = Black;
  700.     new_mprop->diffuse = Black;
  701.     new_mprop->specular = Black;
  702.     new_mprop->shininess = 0.0;
  703.     new_mprop->transparency = 0.0;
  704.     new_mprop->reflection = 0.0;
  705.     new_mprop->self_illum = FALSE;
  706.  
  707.     strcpy (new_mprop->tex_map, "");
  708.     new_mprop->tex_strength = 0.0;
  709.  
  710.     strcpy (new_mprop->bump_map, "");
  711.     new_mprop->bump_strength = 0.0;
  712.  
  713.     return new_mprop;
  714. }
  715.  
  716.  
  717. /* Load in any predefined materials */
  718. void read_library (char *fname)
  719. {
  720.     FILE *lib;
  721.     char string[256], name[80];
  722.  
  723.     if ((lib = fopen (fname, "r")) == NULL) {
  724.     printf ("Cannot open texture library file %s!\n", fname);
  725.     exit(1);
  726.     }
  727.  
  728.     switch (format) {
  729.     case POV10:
  730.     case POV20:
  731.         while (fgets (string, 256, lib) != NULL) {
  732.         if (strstr (string, "#declare")) {
  733.             strcpy (name, between (string, "#declare", "="));
  734.             cleanup_name (name);
  735.             (void)update_materials (name, TRUE);
  736.         }
  737.         }
  738.         break;
  739.  
  740.     case VIVID:
  741.         while (fgets (string, 256, lib) != NULL) {
  742.         if (strstr (string, "#define")) {
  743.             (void)parse_string (string);
  744.             strcpy (name, parse_string (NULL));
  745.             cleanup_name (name);
  746.             (void)update_materials (name, TRUE);
  747.         }
  748.         }
  749.         break;
  750.  
  751.     case POLYRAY:
  752.         while (fgets (string, 256, lib) != NULL) {
  753.         if (strstr (string, "define")) {
  754.             (void)parse_string (string);
  755.             strcpy (name, parse_string (NULL));
  756.             cleanup_name (name);
  757.             (void)update_materials (name, TRUE);
  758.         }
  759.         }
  760.         break;
  761.     }
  762.  
  763.     fclose (lib);
  764. }
  765.  
  766.  
  767. void write_intro (FILE *f)
  768. {
  769.     int i;
  770.  
  771.     switch (format) {
  772.     case POV10:
  773.     case POV20:
  774.         fprintf (f, "#include \"colors.inc\"\n");
  775.         fprintf (f, "#include \"shapes.inc\"\n");
  776.         fprintf (f, "#include \"textures.inc\"\n");
  777.  
  778.         for (i = 0; i < MAX_LIB; i++) {
  779.         if (strlen(libname[i]) > 0)
  780.             fprintf (f, "#include \"%s\"\n", libname[i]);
  781.         }
  782.  
  783.         fprintf (f, "\n");
  784.         break;
  785.  
  786.     case VIVID:
  787.         fprintf (f, "#include color.vc\n");
  788.  
  789.         for (i = 0; i < MAX_LIB; i++) {
  790.         if (strlen(libname[i]) > 0)
  791.             fprintf (f, "#include %s\n", libname[i]);
  792.         }
  793.  
  794.         fprintf (f, "\n");
  795.         break;
  796.  
  797.     case POLYRAY:
  798.         fprintf (f, "include \"colors.inc\"\n");
  799.  
  800.         for (i = 0; i < MAX_LIB; i++) {
  801.         if (strlen(libname[i]) > 0)
  802.             fprintf (f, "include \"%s\"\n", libname[i]);
  803.         }
  804.  
  805.         fprintf (f, "\n");
  806.         break;
  807.     }
  808. }
  809.  
  810.  
  811. /* Write the object summary */
  812. void write_summary (FILE *f)
  813. {
  814.     Summary *s;
  815.  
  816.     if (summary == NULL)
  817.         return;
  818.  
  819.     fprintf (f, "//   Object    CenterX    CenterY    CenterZ    LengthX    LengthY    LengthZ\n");
  820.     fprintf (f, "// ---------- ---------- ---------- ---------- ---------- ---------- ----------\n");
  821.  
  822.     for (s = summary; s != NULL; s = s->next) {
  823.         fprintf (f, "// %-10s%11.2f%11.2f%11.2f%11.2f%11.2f%11.2f\n",
  824.          s->name, s->center[X], s->center[Y], s->center[Z],
  825.          s->lengths[X], s->lengths[Y], s->lengths[Z]);
  826.     }
  827.  
  828.     fprintf (f, "\n");
  829. }
  830.  
  831.  
  832. /* Write background solid colour */
  833. void write_bgsolid (FILE *f, Colour col)
  834. {
  835.     switch (format) {
  836.     case POV10:
  837.         fprintf (f, "/* Background colour */\n");
  838.         fprintf (f, "object {\n");
  839.         fprintf (f, "   sphere { <0.0 0.0 0.0> 1e6 }\n");
  840.         fprintf (f, "   texture {\n");
  841.         fprintf (f, "      ambient 1.0\n");
  842.         fprintf (f, "      diffuse 0.0\n");
  843.         fprintf (f, "      color red %4.2f green %4.2f blue %4.2f\n",
  844.                  col.red, col.green, col.blue);
  845.         fprintf (f, "   }\n");
  846.         fprintf (f, "}\n\n");
  847.         break;
  848.  
  849.     case POV20:
  850.         fprintf (f, "background { color red %4.2f green %4.2f blue %4.2f }\n\n",
  851.                col.red, col.green, col.blue);
  852.         break;
  853.  
  854.     case POLYRAY:
  855.         fprintf (f, "background <%4.2f, %4.2f, %4.2f>\n\n",
  856.                col.red, col.green, col.blue);
  857.         break;
  858.     }
  859. }
  860.  
  861.  
  862. void write_light (FILE *f, char *name, Vector pos, Colour col)
  863. {
  864.     switch (format) {
  865.     case POV10:
  866.         fprintf (f, "/* Light: %s */\n", name);
  867.         fprintf (f, "object {\n");
  868.         fprintf (f, "    light_source { <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f }\n",
  869.             pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
  870.         fprintf (f, "}\n\n");
  871.         break;
  872.  
  873.     case POV20:
  874.         fprintf (f, "/* Light: %s */\n", name);
  875.         fprintf (f, "light_source {\n");
  876.         fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
  877.              pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
  878.         fprintf (f, "}\n\n");
  879.         break;
  880.  
  881.     case VIVID:
  882.         fprintf (f, "/* Light: %s */\n", name);
  883.         fprintf (f, "light {\n");
  884.         fprintf (f, "    type point\n");
  885.         fprintf (f, "    position %.4f %.4f %.4f\n",
  886.                  pos[X], pos[Y], pos[Z]);
  887.         fprintf (f, "    color %4.2f %4.2f %4.2f\n",
  888.                  col.red, col.green, col.blue);
  889.         fprintf (f, "}\n\n");
  890.         break;
  891.  
  892.     case POLYRAY:
  893.         fprintf (f, "// Light: %s\n", name);
  894.         fprintf (f, "light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>\n\n",
  895.              col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
  896.         break;
  897.     }
  898. }
  899.  
  900.  
  901. void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
  902.               float hotspot, float falloff)
  903. {
  904.     switch (format) {
  905.     case POV10:
  906.         fprintf (f, "/* Spotlight: %s */\n", name);
  907.         fprintf (f, "object {\n");
  908.         fprintf (f, "    light_source {\n");
  909.         fprintf (f, "        <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f\n",
  910.                    pos[X], pos[Y], pos[Z],
  911.                    col.red, col.green, col.blue);
  912.         fprintf (f, "        spotlight\n");
  913.         fprintf (f, "        point_at <%.4f %.4f %.4f>\n",
  914.                    target[X], target[Y], target[Z]);
  915.         fprintf (f, "        tightness 0\n");
  916.         fprintf (f, "        radius %.2f\n", 0.5*hotspot);
  917.         fprintf (f, "        falloff %.2f\n", 0.5*falloff);
  918.         fprintf (f, "    }\n");
  919.         fprintf (f, "}\n\n");
  920.         break;
  921.  
  922.     case POV20:
  923.         fprintf (f, "/* Spotlight: %s */\n", name);
  924.         fprintf (f, "light_source {\n");
  925.         fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
  926.                  pos[X], pos[Y], pos[Z],
  927.                  col.red, col.green, col.blue);
  928.         fprintf (f, "    spotlight\n");
  929.         fprintf (f, "    point_at <%.4f, %.4f, %.4f>\n",
  930.                  target[X], target[Y], target[Z]);
  931.         fprintf (f, "    tightness 0\n");
  932.         fprintf (f, "    radius %.2f\n", 0.5*hotspot);
  933.         fprintf (f, "    falloff %.2f\n", 0.5*falloff);
  934.         fprintf (f, "}\n\n");
  935.         break;
  936.  
  937.     case VIVID:
  938.         fprintf (f, "/* Spotlight: %s */\n", name);
  939.         fprintf (f, "light {\n");
  940.         fprintf (f, "    type spot\n");
  941.         fprintf (f, "    position %.4f %.4f %.4f\n",
  942.                  pos[X], pos[Y], pos[Z]);
  943.         fprintf (f, "    at %.4f %.4f %.4f\n",
  944.                  target[X], target[Y], target[Z]);
  945.         fprintf (f, "    color %4.2f %4.2f %4.2f\n",
  946.                  col.red, col.green, col.blue);
  947.         fprintf (f, "    min_angle %.2f\n", hotspot);
  948.         fprintf (f, "    max_angle %.2f\n", falloff);
  949.         fprintf (f, "}\n\n");
  950.         break;
  951.  
  952.     case POLYRAY:
  953.         fprintf (f, "// Spotlight: %s\n", name);
  954.         fprintf (f, "spot_light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>,\n",
  955.               col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
  956.         fprintf (f, "           <%.4f, %.4f, %.4f>, 0.0, %.2f, %.2f\n\n",
  957.               target[X], target[Y], target[Z], hotspot/2.0, falloff/2.0);
  958.         break;
  959.     }
  960. }
  961.  
  962.  
  963. void write_fog (FILE *f, Colour col, float dist)
  964. {
  965.     if (dist <= 0.0)
  966.     return;
  967.  
  968.     switch (format) {
  969.     case POV10:
  970.         fprintf (f, "fog {\n");
  971.         fprintf (f, "    color red %4.2f green %4.2f blue %4.2f %.4f\n",
  972.               col.red, col.green, col.blue, dist/2.0);
  973.         fprintf (f, "}\n\n");
  974.         break;
  975.  
  976.     case POV20:
  977.         fprintf (f, "fog {\n");
  978.         fprintf (f, "    color red %4.2f green %4.2f blue %4.2f distance %.4f\n",
  979.               col.red, col.green, col.blue, dist/2.0);
  980.         fprintf (f, "}\n\n");
  981.         break;
  982.     }
  983. }
  984.  
  985.  
  986. void write_camera (FILE *f, char *name, Vector pos, Vector target,
  987.                 float lens, float bank)
  988. {
  989.     float fov;
  990.  
  991.     cameras++;
  992.  
  993.     fov = findfov (lens);
  994.  
  995.     switch (format) {
  996.     case POV10:
  997.         /* Comment out multiple cameras */
  998.         if (cameras > 1)
  999.         fprintf (f, "/*\n");
  1000.  
  1001.         fprintf (f, "/* Camera: %s */\n", name);
  1002.         fprintf (f, "camera {\n");
  1003.         fprintf (f, "   location <%.4f %.4f %.4f>\n",
  1004.                   pos[X], pos[Y], pos[Z]);
  1005.         fprintf (f, "   direction <0 %.3f 0>\n", 0.60/tan(0.5*RAD(fov)) );
  1006.         fprintf (f, "   up <0 0 1>\n");
  1007.         fprintf (f, "   sky  <0 0 1>\n");
  1008.         fprintf (f, "   right <%.3f 0 0>\n", ASPECT);
  1009.         fprintf (f, "   look_at <%.4f %.4f %.4f>\n",
  1010.                   target[X], target[Y], target[Z]);
  1011.         if (bank != 0.0)
  1012.         fprintf (f, "   /* Bank angle = %.2f */\n", bank);
  1013.  
  1014.         fprintf (f, "}\n");
  1015.  
  1016.         if (cameras > 1)
  1017.         fprintf (f, "*/\n");
  1018.  
  1019.         fprintf (f, "\n");
  1020.         break;
  1021.  
  1022.     case POV20:
  1023.         /* Comment out multiple cameras */
  1024.         if (cameras > 1)
  1025.         fprintf (f, "/*\n");
  1026.  
  1027.         fprintf (f, "/* Camera: %s */\n", name);
  1028.         fprintf (f, "camera {\n");
  1029.         fprintf (f, "   location <%.4f, %.4f, %.4f>\n",
  1030.                   pos[X], pos[Y], pos[Z]);
  1031.         fprintf (f, "   direction <0, %.3f, 0>\n", 0.60/tan(0.5*RAD(fov)) );
  1032.         fprintf (f, "   up <0, 0, 1>\n");
  1033.         fprintf (f, "   sky  <0, 0, 1>\n");
  1034.         fprintf (f, "   right <%.3f, 0, 0>\n", ASPECT);
  1035.         fprintf (f, "   look_at <%.4f, %.4f, %.4f>\n",
  1036.                   target[X], target[Y], target[Z]);
  1037.         if (bank != 0.0)
  1038.         fprintf (f, "   /* Bank angle = %.2f */\n", bank);
  1039.  
  1040.         fprintf (f, "}\n");
  1041.  
  1042.         if (cameras > 1)
  1043.         fprintf (f, "*/\n");
  1044.  
  1045.         fprintf (f, "\n");
  1046.         break;
  1047.  
  1048.     case VIVID:
  1049.         fprintf (f, "/* Camera: %s */\n", name);
  1050.  
  1051.         if (cameras > 1)
  1052.         fprintf (f, "/*\n");
  1053.  
  1054.         fprintf (f, "studio {\n");
  1055.         fprintf (f, "    from %.4f %.4f %.4f\n",
  1056.                    pos[X], pos[Y], pos[Z]);
  1057.         fprintf (f, "    at %.4f %.4f %.4f\n",
  1058.                    target[X], target[Y], target[Z]);
  1059.         fprintf (f, "    up 0 0 1\n");
  1060.         fprintf (f, "    angle %.2f\n", 1.1*fov);
  1061.         fprintf (f, "    aspect %.3f\n", ASPECT);
  1062.         fprintf (f, "    resolution 320 200\n");
  1063.         fprintf (f, "    antialias none\n");
  1064.         fprintf (f, "}\n");
  1065.  
  1066.         if (cameras > 1)
  1067.         fprintf (f, "*/\n");
  1068.  
  1069.         fprintf (f, "\n");
  1070.         break;
  1071.  
  1072.     case POLYRAY:
  1073.         if (cameras == 1) {
  1074.         fprintf (f, "// Camera: %s\n", name);
  1075.         fprintf (f, "viewpoint {\n");
  1076.         fprintf (f, "    from <%.4f, %.4f, %.4f>\n",
  1077.                    pos[X], pos[Y], pos[Z]);
  1078.         fprintf (f, "    at <%.4f, %.4f, %.4f>\n",
  1079.                    target[X], target[Y], target[Z]);
  1080.         fprintf (f, "    up <0, 0, 1>\n");
  1081.         fprintf (f, "    angle %.2f\n", 0.85*fov);
  1082.         fprintf (f, "    aspect %.3f\n", -(ASPECT));
  1083.         fprintf (f, "    resolution 320, 200\n");
  1084.         fprintf (f, "}\n");
  1085.         }
  1086.  
  1087.         fprintf (f, "\n");
  1088.         break;
  1089.     }
  1090. }
  1091.  
  1092.  
  1093. void write_material (FILE *f, char *mat)
  1094. {
  1095.     MatProp *mprop = LIST_FIND (mprop_list, mat);
  1096.  
  1097.     if (mprop == NULL)
  1098.        mprop = &DefaultMaterial;
  1099.  
  1100.     switch (format) {
  1101.     case POV10:
  1102.         write_pov10_material (f, mprop);
  1103.         break;
  1104.  
  1105.     case POV20:
  1106.         write_pov20_material (f, mprop);
  1107.         break;
  1108.  
  1109.     case VIVID:
  1110.         write_vivid_material (f, mprop);
  1111.         break;
  1112.  
  1113.     case POLYRAY:
  1114.         write_polyray_material (f, mprop);
  1115.         break;
  1116.     }
  1117. }
  1118.  
  1119.  
  1120. void write_pov10_material (FILE *f, MatProp *m)
  1121. {
  1122.     float amb = 0.1, dif = 0.9, spec = 1.0;
  1123.     float dist_white, dist_diff, phong, phong_size;
  1124.     float red, green, blue;
  1125.  
  1126.     /* amb = get_ambient (m); */
  1127.  
  1128.     if (m->self_illum) {
  1129.     amb = 0.9;
  1130.     dif = 0.1;
  1131.     }
  1132.  
  1133.     dist_white = fabs(1.0 - m->specular.red) +
  1134.          fabs(1.0 - m->specular.green) +
  1135.          fabs(1.0 - m->specular.blue);
  1136.  
  1137.     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
  1138.          fabs(m->diffuse.green - m->specular.green) +
  1139.          fabs(m->diffuse.blue  - m->specular.blue);
  1140.  
  1141.  
  1142.     phong_size = 0.7*m->shininess;
  1143.     if (phong_size < 1.0) phong_size = 1.0;
  1144.  
  1145.     if (phong_size > 30.0)
  1146.     phong = 1.0;
  1147.     else
  1148.     phong = phong_size/30.0;
  1149.  
  1150.     fprintf (f, "#declare %s = texture {\n", m->name);
  1151.     fprintf (f, "    ambient %.2f\n", amb);
  1152.     fprintf (f, "    diffuse %.2f\n", dif);
  1153.     fprintf (f, "    phong %.2f\n", phong);
  1154.     fprintf (f, "    phong_size %.1f\n", phong_size);
  1155.  
  1156.     if (dist_diff < dist_white)
  1157.     fprintf (f, "    metallic\n");
  1158.  
  1159.     if (m->reflection > 0.0) {
  1160.     spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
  1161.     fprintf (f, "    reflection %.3f\n", spec * m->reflection);
  1162.     }
  1163.  
  1164.     if (m->transparency > 0.0) {
  1165.     red   = m->diffuse.red;
  1166.     green = m->diffuse.green;
  1167.     blue  = m->diffuse.blue;
  1168.  
  1169.     /* Saturate the colour towards white as the transparency increases */
  1170.     red   = ((1.0 - m->transparency) * red)   + m->transparency;
  1171.     green = ((1.0 - m->transparency) * green) + m->transparency;
  1172.     blue  = ((1.0 - m->transparency) * blue)  + m->transparency;
  1173.  
  1174.     fprintf (f, "    color red %.3f green %.3f blue %.3f alpha %.3f\n",
  1175.              red, green, blue, m->transparency);
  1176.     fprintf (f, "    ior 1.1\n");
  1177.     fprintf (f, "    refraction 1.0\n");
  1178.     }
  1179.     else
  1180.     fprintf (f, "    color red %.3f green %.3f blue %.3f\n",
  1181.              m->diffuse.red, m->diffuse.green, m->diffuse.blue);
  1182.  
  1183.     if (strlen (m->tex_map) > 0) {
  1184.     fprintf (f, "    /* Image map: %s, Strength: %.2f */\n",
  1185.              m->tex_map, m->tex_strength);
  1186.     }
  1187.  
  1188.     if (strlen (m->bump_map) > 0) {
  1189.     fprintf (f, "    /* Bump map: %s, Strength: %.2f */\n",
  1190.              m->bump_map, m->bump_strength);
  1191.     }
  1192.  
  1193.     fprintf (f, "}\n\n");
  1194. }
  1195.  
  1196.  
  1197. void write_pov20_material (FILE *f, MatProp *m)
  1198. {
  1199.     float amb = 0.1, dif = 0.9, spec = 1.0;
  1200.     float dist_white, dist_diff, phong, phong_size;
  1201.     float red, green, blue;
  1202.  
  1203.     /* amb = get_ambient (m); */
  1204.  
  1205.     if (m->self_illum) {
  1206.     amb = 0.9;
  1207.     dif = 0.1;
  1208.     }
  1209.  
  1210.     dist_white = fabs(1.0 - m->specular.red) +
  1211.          fabs(1.0 - m->specular.green) +
  1212.          fabs(1.0 - m->specular.blue);
  1213.  
  1214.     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
  1215.          fabs(m->diffuse.green - m->specular.green) +
  1216.          fabs(m->diffuse.blue  - m->specular.blue);
  1217.  
  1218.     phong_size = 0.7*m->shininess;
  1219.     if (phong_size < 1.0) phong_size = 1.0;
  1220.  
  1221.     if (phong_size > 30.0)
  1222.     phong = 1.0;
  1223.     else
  1224.     phong = phong_size/30.0;
  1225.  
  1226.     fprintf (f, "#declare %s = texture {\n", m->name);
  1227.     fprintf (f, "    finish {\n");
  1228.     fprintf (f, "        ambient %.2f\n", amb);
  1229.     fprintf (f, "        diffuse %.2f\n", dif);
  1230.     fprintf (f, "        phong %.2f\n", phong);
  1231.     fprintf (f, "        phong_size %.1f\n", phong_size);
  1232.  
  1233.     if (dist_diff < dist_white)
  1234.     fprintf (f, "        metallic\n");
  1235.  
  1236.     if (m->reflection > 0.0) {
  1237.     spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
  1238.     fprintf (f, "        reflection %.3f\n", spec * m->reflection);
  1239.     }
  1240.  
  1241.     if (m->transparency > 0.0) {
  1242.     fprintf (f, "        ior 1.1\n");
  1243.     fprintf (f, "        refraction 1.0\n");
  1244.     }
  1245.  
  1246.     fprintf (f, "    }\n");
  1247.  
  1248.     if (m->transparency > 0.0) {
  1249.     red   = m->diffuse.red;
  1250.     green = m->diffuse.green;
  1251.     blue  = m->diffuse.blue;
  1252.  
  1253.     /* Saturate the colour towards white as the transparency increases */
  1254.     red   = ((1.0 - m->transparency) * red)   + m->transparency;
  1255.     green = ((1.0 - m->transparency) * green) + m->transparency;
  1256.     blue  = ((1.0 - m->transparency) * blue)  + m->transparency;
  1257.  
  1258.     fprintf (f, "    pigment { rgbf <%.3f, %.3f, %.3f, %.3f> }\n",
  1259.             red, green, blue, m->transparency);
  1260.     }
  1261.     else
  1262.     fprintf (f, "    pigment { rgb <%.3f, %.3f, %.3f> }\n",
  1263.             m->diffuse.red, m->diffuse.green, m->diffuse.blue);
  1264.  
  1265.     if (strlen (m->tex_map) > 0) {
  1266.     fprintf (f, "    /* Image map: %s, Strength: %.2f */\n",
  1267.              m->tex_map, m->tex_strength);
  1268.     }
  1269.  
  1270.     if (strlen (m->bump_map) > 0) {
  1271.     fprintf (f, "    /* Bump map: %s, Strength: %.2f */\n",
  1272.              m->bump_map, m->bump_strength);
  1273.     }
  1274.  
  1275.     fprintf (f, "}\n\n");
  1276. }
  1277.  
  1278.  
  1279. void write_vivid_material (FILE *f, MatProp *m)
  1280. {
  1281.     float amb = 0.1, dif = 0.9;
  1282.  
  1283.     /* amb = get_ambient (m); */
  1284.  
  1285.     if (m->self_illum) {
  1286.     amb = 0.9;
  1287.     dif = 0.1;
  1288.     }
  1289.  
  1290.     if (m->transparency > 0.0) {
  1291.        dif = dif - m->transparency;
  1292.        if (dif < 0.0) dif = 0.0;
  1293.     }
  1294.  
  1295.     fprintf (f, "#define %s \\ \n", m->name);
  1296.     fprintf (f, "    surface {           \\ \n");
  1297.     fprintf (f, "        ambient %.3f %.3f %.3f \\ \n",
  1298.              amb*m->ambient.red, amb*m->ambient.green, amb*m->ambient.blue);
  1299.  
  1300.     fprintf (f, "        diffuse %.3f %.3f %.3f \\ \n",
  1301.              dif*m->diffuse.red, dif*m->diffuse.green, dif*m->diffuse.blue);
  1302.  
  1303.     fprintf (f, "        shine %.1f  %.3f %.3f %.3f \\ \n",
  1304.              0.7*m->shininess, m->specular.red, m->specular.green, m->specular.blue);
  1305.  
  1306.     if (m->transparency > 0.0) {
  1307.     fprintf (f, "        transparent %.3f*white \\ \n", 1.0 - (1.0 - m->transparency)/14.0);
  1308.     fprintf (f, "        ior 1.1 \\ \n");
  1309.     }
  1310.  
  1311.     if (m->reflection > 0.0)
  1312.     fprintf (f, "        specular %.3f*white \\ \n", m->reflection);
  1313.  
  1314.     if (strlen (m->tex_map) > 0) {
  1315.     fprintf (f, "        /* Image map: %s, Strength: %.2f */ \\ \n",
  1316.                  m->tex_map, m->tex_strength);
  1317.     }
  1318.  
  1319.     if (strlen (m->bump_map) > 0) {
  1320.     fprintf (f, "        /* Bump map: %s, Strength: %.2f */ \\ \n",
  1321.                  m->bump_map, m->bump_strength);
  1322.     }
  1323.  
  1324.     fprintf (f, "    }\n\n");
  1325. }
  1326.  
  1327.  
  1328. void write_polyray_material (FILE *f, MatProp *m)
  1329. {
  1330.     float amb = 0.1, dif = 0.9, spec;
  1331.  
  1332.     /* amb = get_ambient (m); */
  1333.  
  1334.     if (m->self_illum) {
  1335.     amb = 0.9;
  1336.     dif = 0.1;
  1337.     }
  1338.  
  1339.     if (m->transparency > 0.0) {
  1340.        dif = dif - m->transparency;
  1341.        if (dif < 0.0) dif = 0.0;
  1342.     }
  1343.  
  1344.     if (m->shininess == 0.0)
  1345.     m->shininess = 0.1;
  1346.  
  1347.     if (m->shininess > 40.0)
  1348.     spec = 1.0;
  1349.     else
  1350.     spec = m->shininess/40.0;
  1351.  
  1352.     fprintf (f, "define %s\n", m->name);
  1353.     fprintf (f, "texture {\n");
  1354.     fprintf (f, "    surface {\n");
  1355.     fprintf (f, "        ambient <%.3f, %.3f, %.3f>, %.1f\n",
  1356.              m->ambient.red, m->ambient.green, m->ambient.blue, amb);
  1357.  
  1358.     fprintf (f, "        diffuse <%.3f, %.3f, %.3f>, %.1f\n",
  1359.              m->diffuse.red, m->diffuse.green, m->diffuse.blue, dif);
  1360.  
  1361.     fprintf (f, "        specular <%.3f, %.3f, %.3f>, %.2f\n",
  1362.              m->specular.red, m->specular.green, m->specular.blue, spec);
  1363.  
  1364.     fprintf (f, "        microfacet Reitz %.1f\n", 400.0/m->shininess);
  1365.  
  1366.     if (m->transparency > 0.0)
  1367.     fprintf (f, "        transmission %.3f, 1.1\n", m->transparency);
  1368.  
  1369.     if (m->reflection > 0.0)
  1370.     fprintf (f, "        reflection %.3f\n", m->reflection);
  1371.  
  1372.     if (strlen (m->tex_map) > 0) {
  1373.     fprintf (f, "        // Image map: %s, Strength: %.2f\n",
  1374.                  m->tex_map, m->tex_strength);
  1375.     }
  1376.  
  1377.     if (strlen (m->bump_map) > 0) {
  1378.     fprintf (f, "        // Bump map: %s, Strength: %.2f\n",
  1379.                  m->bump_map, m->bump_strength);
  1380.     }
  1381.  
  1382.     fprintf (f, "    }\n");
  1383.     fprintf (f, "}\n\n");
  1384. }
  1385.  
  1386.  
  1387. /* Write a mesh file */
  1388. void write_mesh (FILE *f, Mesh *mesh)
  1389. {
  1390.     int i;
  1391.     Vector va, vb, vc;
  1392.     Summary *new_summary;
  1393.     Matrix obj_matrix;
  1394.  
  1395.     if (mesh->hidden || LIST_FIND (excl_list, mesh->name))
  1396.     return;
  1397.  
  1398.     /* Add this object's stats to the summary */
  1399.     new_summary = malloc (sizeof(*new_summary));
  1400.     if (new_summary == NULL)
  1401.     abortmsg ("Out of memory adding summary", 1);
  1402.  
  1403.     strcpy (new_summary->name, mesh->name);
  1404.     vect_copy (new_summary->center,  mesh->center);
  1405.     vect_copy (new_summary->lengths, mesh->lengths);
  1406.  
  1407.     LIST_INSERT (summary, new_summary);
  1408.  
  1409.     /* Compute the object transformation matrix for animations */
  1410.     if (ani_matrix != NULL) {
  1411.     mat_copy (obj_matrix, *ani_matrix);
  1412.     if (vue_version > 2.0)
  1413.         mat_mult (obj_matrix, mesh->invmatrix, obj_matrix);
  1414.     }
  1415.  
  1416.     switch (format) {
  1417.     case POV10:
  1418.     case POV20:
  1419.     case VIVID:
  1420.     case POLYRAY:
  1421.         opt_set_vert (mesh->vertices);
  1422.  
  1423.         for (i = 0; i < mesh->faces; i++) {
  1424.         vect_copy (va, mesh->vertex[mesh->face[i].a]);
  1425.         vect_copy (vb, mesh->vertex[mesh->face[i].b]);
  1426.         vect_copy (vc, mesh->vertex[mesh->face[i].c]);
  1427.  
  1428.         opt_set_texture (mesh->mtl[i]->name);
  1429.  
  1430.         opt_add_tri (va[X], va[Y], va[Z], vc[X], vc[Y], vc[Z],
  1431.                  vb[X], vb[Y], vb[Z]);
  1432.         }
  1433.  
  1434.         fclose (f);
  1435.  
  1436.         if (ani_matrix != NULL)
  1437.         opt_set_transform (obj_matrix);
  1438.  
  1439.         if (box_all || LIST_FIND (box_list, mesh->name))
  1440.         opt_write_box (mesh->name);
  1441.         else
  1442.         opt_write_file (mesh->name);
  1443.  
  1444.         f = fopen (outname, "a");
  1445.         break;
  1446.  
  1447.     case RAW:
  1448.         fprintf (f, "%s\n", mesh->name);
  1449.  
  1450.         for (i = 0; i < mesh->faces; i++) {
  1451.         vect_copy (va, mesh->vertex[mesh->face[i].a]);
  1452.         vect_copy (vb, mesh->vertex[mesh->face[i].b]);
  1453.         vect_copy (vc, mesh->vertex[mesh->face[i].c]);
  1454.  
  1455.         if (ani_matrix != NULL) {
  1456.             vect_transform (va, va, obj_matrix);
  1457.             vect_transform (vb, vb, obj_matrix);
  1458.             vect_transform (vc, vc, obj_matrix);
  1459.         }
  1460.  
  1461.         fprintf (f, "%f %f %f   %f %f %f   %f %f %f\n",
  1462.                 va[X], va[Y], va[Z], vb[X], vb[Y], vb[Z],
  1463.                 vc[X], vc[Y], vc[Z]);
  1464.         }
  1465.  
  1466.         break;
  1467.     }
  1468. }
  1469.  
  1470.  
  1471. /* Parses an object transformation and returns a pointer to the
  1472.    newly allocated transformation */
  1473. Transform *parse_transform (char *string)
  1474. {
  1475.     Transform *t;
  1476.     char      *token;
  1477.     int       token_no;
  1478.  
  1479.     t = (Transform *)malloc (sizeof(*t));
  1480.     if (t == NULL)
  1481.     abortmsg ("Out of memory allocating transform", 1);
  1482.  
  1483.     mat_identity (t->matrix);
  1484.  
  1485.     token = parse_string (string);
  1486.     token_no = 0;
  1487.  
  1488.     while (strlen(token) > 0) {
  1489.      switch (token_no) {
  1490.          case  0: break;
  1491.          case  1: strcpy (t->name, token); break;
  1492.          case  2: t->matrix[0][0] = atof(token); break;
  1493.          case  3: t->matrix[0][1] = atof(token); break;
  1494.          case  4: t->matrix[0][2] = atof(token); break;
  1495.          case  5: t->matrix[1][0] = atof(token); break;
  1496.          case  6: t->matrix[1][1] = atof(token); break;
  1497.          case  7: t->matrix[1][2] = atof(token); break;
  1498.          case  8: t->matrix[2][0] = atof(token); break;
  1499.          case  9: t->matrix[2][1] = atof(token); break;
  1500.          case 10: t->matrix[2][2] = atof(token); break;
  1501.          case 11: t->matrix[3][0] = atof(token); break;
  1502.          case 12: t->matrix[3][1] = atof(token); break;
  1503.          case 13: t->matrix[3][2] = atof(token); break;
  1504.  
  1505.          default: abortmsg ("Error parsing transform", 1);
  1506.      }
  1507.  
  1508.      token = parse_string (NULL);
  1509.      token_no++;
  1510.     }
  1511.  
  1512.     t->matrix[0][3] = 0.0;
  1513.     t->matrix[1][3] = 0.0;
  1514.     t->matrix[2][3] = 0.0;
  1515.     t->matrix[3][3] = 1.0;
  1516.  
  1517.     cleanup_name (t->name);
  1518.  
  1519.     return t;
  1520. }
  1521.  
  1522.  
  1523. /* Parses a morph command and returns a pointer to the
  1524.    newly allocated morph */
  1525. Morph *parse_morph (char *string)
  1526. {
  1527.     Morph  *m;
  1528.     char   *token;
  1529.     int    i, token_no;
  1530.  
  1531.     m = (Morph *)malloc (sizeof(*m));
  1532.     if (m == NULL)
  1533.     abortmsg ("Out of memory allocating morph", 1);
  1534.  
  1535.     mat_identity (m->matrix);
  1536.  
  1537.     token = parse_string (string);
  1538.  
  1539.     token = parse_string (NULL);
  1540.     strcpy (m->name, token);
  1541.  
  1542.     token = parse_string (NULL);
  1543.     m->count = atoi (token);
  1544.  
  1545.     if (strlen (m->name) == 0 || m->count < 1 || m->count > 4)
  1546.     abortmsg ("Error parsing morph command", 1);
  1547.  
  1548.     cleanup_name (m->name);
  1549.  
  1550.     for (i = 0; i < m->count; i++) {
  1551.     token = parse_string (NULL);
  1552.     strcpy (m->names[i], token);
  1553.  
  1554.     token = parse_string (NULL);
  1555.     m->weight[i] = atof (token);
  1556.  
  1557.     if (strlen (m->names[i]) == 0)
  1558.         abortmsg ("Error parsing morph command", 1);
  1559.  
  1560.     cleanup_name (m->names[i]);
  1561.     }
  1562.  
  1563.     token = parse_string (NULL);
  1564.     token_no = 0;
  1565.  
  1566.     while (strlen(token) > 0) {
  1567.      switch (token_no) {
  1568.          case  0: m->matrix[0][0] = atof(token); break;
  1569.          case  1: m->matrix[0][1] = atof(token); break;
  1570.          case  2: m->matrix[0][2] = atof(token); break;
  1571.          case  3: m->matrix[1][0] = atof(token); break;
  1572.          case  4: m->matrix[1][1] = atof(token); break;
  1573.          case  5: m->matrix[1][2] = atof(token); break;
  1574.          case  6: m->matrix[2][0] = atof(token); break;
  1575.          case  7: m->matrix[2][1] = atof(token); break;
  1576.          case  8: m->matrix[2][2] = atof(token); break;
  1577.          case  9: m->matrix[3][0] = atof(token); break;
  1578.          case 10: m->matrix[3][1] = atof(token); break;
  1579.          case 11: m->matrix[3][2] = atof(token); break;
  1580.  
  1581.          default: abortmsg ("Error parsing morph command", 1);
  1582.      }
  1583.  
  1584.      token = parse_string (NULL);
  1585.      token_no++;
  1586.     }
  1587.  
  1588.     m->matrix[0][3] = 0.0;
  1589.     m->matrix[1][3] = 0.0;
  1590.     m->matrix[2][3] = 0.0;
  1591.     m->matrix[3][3] = 1.0;
  1592.  
  1593.     return m;
  1594. }
  1595.  
  1596.  
  1597. /* Parses an omni light and returns a pointer to the
  1598.    newly allocated light */
  1599. OmniLight *parse_omnilight (char *string)
  1600. {
  1601.     OmniLight *o;
  1602.     char      *token;
  1603.     int       token_no;
  1604.  
  1605.     o = (OmniLight *)malloc (sizeof(*o));
  1606.     if (o == NULL)
  1607.     abortmsg ("Out of memory allocating omnilight", 1);
  1608.  
  1609.     token = parse_string (string);
  1610.     token_no = 0;
  1611.  
  1612.     while (strlen(token) > 0) {
  1613.      switch (token_no) {
  1614.          case 0: break;
  1615.          case 1: strcpy (o->name, token); break;
  1616.          case 2: o->pos[X] = atof (token); break;
  1617.          case 3: o->pos[Y] = atof (token); break;
  1618.          case 4: o->pos[Z] = atof (token); break;
  1619.          case 5: o->col.red   = atof (token); break;
  1620.          case 6: o->col.green = atof (token); break;
  1621.          case 7: o->col.blue  = atof (token); break;
  1622.  
  1623.          default: abortmsg ("Error parsing omnilight", 1);
  1624.      }
  1625.  
  1626.      token = parse_string (NULL);
  1627.      token_no++;
  1628.     }
  1629.  
  1630.     cleanup_name (o->name);
  1631.  
  1632.     return o;
  1633. }
  1634.  
  1635.  
  1636. /* Parses a spotlight and returns a pointer to the
  1637.    newly allocated spotlight */
  1638. Spotlight *parse_spotlight (char *string)
  1639. {
  1640.     Spotlight *s;
  1641.     char      *token;
  1642.     int       token_no;
  1643.  
  1644.     s = (Spotlight *)malloc (sizeof(*s));
  1645.     if (s == NULL)
  1646.     abortmsg ("Out of memory allocating spotlight", 1);
  1647.  
  1648.     token = parse_string (string);
  1649.     token_no = 0;
  1650.  
  1651.     while (strlen(token) > 0) {
  1652.      switch (token_no) {
  1653.          case  0: break;
  1654.          case  1: strcpy (s->name, token); break;
  1655.          case  2: s->pos[X] = atof (token); break;
  1656.          case  3: s->pos[Y] = atof (token); break;
  1657.          case  4: s->pos[Z] = atof (token); break;
  1658.          case  5: s->target[X] = atof (token); break;
  1659.          case  6: s->target[Y] = atof (token); break;
  1660.          case  7: s->target[Z] = atof (token); break;
  1661.          case  8: s->col.red   = atof (token); break;
  1662.          case  9: s->col.green = atof (token); break;
  1663.          case 10: s->col.blue  = atof (token); break;
  1664.          case 11: s->hotspot   = atof (token); break;
  1665.          case 12: s->falloff   = atof (token); break;
  1666.          case 13: break;
  1667.  
  1668.          default: abortmsg ("Error parsing spotlight", 1);
  1669.      }
  1670.  
  1671.      token = parse_string (NULL);
  1672.      token_no++;
  1673.     }
  1674.  
  1675.     cleanup_name (s->name);
  1676.  
  1677.     return s;
  1678. }
  1679.  
  1680.  
  1681. /* Parses a camera command and returns a pointer to the
  1682.    newly allocated camera */
  1683. Camera *parse_camera (char *string)
  1684. {
  1685.     Camera *c;
  1686.     char   *token;
  1687.     int    token_no;
  1688.  
  1689.     c = (Camera *)malloc (sizeof(*c));
  1690.     if (c == NULL)
  1691.     abortmsg ("Out of memory allocating camera", 1);
  1692.  
  1693.     token = parse_string (string);
  1694.     token_no = 0;
  1695.  
  1696.     while (strlen(token) > 0) {
  1697.      switch (token_no) {
  1698.          case 0: break;
  1699.          case 1: c->pos[X] = atof (token); break;
  1700.          case 2: c->pos[Y] = atof (token); break;
  1701.          case 3: c->pos[Z] = atof (token); break;
  1702.          case 4: c->target[X] = atof (token); break;
  1703.          case 5: c->target[Y] = atof (token); break;
  1704.          case 6: c->target[Z] = atof (token); break;
  1705.          case 7: c->bank = atof (token); break;
  1706.          case 8: c->lens = atof (token); break;
  1707.  
  1708.          default: abortmsg ("Error parsing camera", 1);
  1709.      }
  1710.  
  1711.      token = parse_string (NULL);
  1712.      token_no++;
  1713.     }
  1714.  
  1715.     return c;
  1716. }
  1717.  
  1718.  
  1719. /* Load the transforms, camera movements, etc for the specified frame */
  1720. void read_frame (char *filename, int frame_no)
  1721. {
  1722.     FILE  *f;
  1723.     char  fname[80];
  1724.     char  string[256];
  1725.     char  *token;
  1726.  
  1727.     /* Open the .vue file */
  1728.     strcpy (fname, filename);   /* Make a copy we can mess with */
  1729.     add_ext (fname, "vue", 0);
  1730.  
  1731.     f = fopen (fname, "r");
  1732.     if (f == NULL) {
  1733.     printf ("Error opening file '%s'\n", fname);
  1734.     exit(1);
  1735.     }
  1736.  
  1737.     /* Load the specified frame */
  1738.     find_frame (f, frame_no);
  1739.  
  1740.     while (fgets (string, 256, f) != NULL) {
  1741.     token = parse_string (string);
  1742.  
  1743.     if (strcmp (token, "frame") == 0)
  1744.         break;
  1745.     else if (strcmp (token, "transform") == 0) {
  1746.         LIST_INSERT (trans_list, parse_transform (string));
  1747.     }
  1748.     else if (strcmp (token, "morph") == 0) {
  1749.         LIST_INSERT (morph_list, parse_morph (string));
  1750.     }
  1751.     else if (strcmp (token, "light") == 0) {
  1752.         LIST_INSERT (omni_list, parse_omnilight (string));
  1753.     }
  1754.     else if (strcmp (token, "spotlight") == 0) {
  1755.         LIST_INSERT (spot_list, parse_spotlight (string));
  1756.     }
  1757.     else if (strcmp (token, "camera") == 0) {
  1758.         if (cam_list != NULL)
  1759.         abortmsg ("ERROR - Multiple cameras in .vue file", 1);
  1760.  
  1761.         LIST_INSERT (cam_list, parse_camera (string));
  1762.     }
  1763.     else if (strcmp (token, "top") == 0)
  1764.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1765.     else if (strcmp (token, "bottom") == 0)
  1766.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1767.     else if (strcmp (token, "left") == 0)
  1768.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1769.     else if (strcmp (token, "right") == 0)
  1770.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1771.     else if (strcmp (token, "front") == 0)
  1772.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1773.     else if (strcmp (token, "back") == 0)
  1774.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1775.     else if (strcmp (token, "user") == 0)
  1776.         abortmsg ("ERROR - User viewports are not supported", 1);
  1777.     }
  1778.  
  1779.     fclose(f);
  1780. }
  1781.  
  1782.  
  1783. void find_frame (FILE *f, int frame_no)
  1784. {
  1785.     char  string[256];
  1786.     char  *token;
  1787.     int   frame = 0;
  1788.  
  1789.     /* Search the .vue file for the required frame */
  1790.     while (1) {
  1791.     /* Read the next line in the file */
  1792.     if (fgets (string, 256, f) == NULL) {
  1793.         printf ("Unable to locate frame #%d in .vue file\n", frame_no);
  1794.         exit(1);
  1795.     }
  1796.  
  1797.     token = parse_string (string);
  1798.  
  1799.     if (strcmp (token, "frame") == 0) {
  1800.         token = parse_string (NULL);
  1801.  
  1802.         if (strlen(token) == 0) {
  1803.         printf ("Unable to locate frame #%d in .vue file\n", frame_no);
  1804.         exit(1);
  1805.         }
  1806.  
  1807.         frame = atoi (token);
  1808.  
  1809.         if (frame == frame_no)
  1810.         break;
  1811.     }
  1812.     else if (strcmp (token, "VERSION") == 0) {
  1813.         token = parse_string (NULL);
  1814.  
  1815.         vue_version = atoi(token) / 100.0;
  1816.     }
  1817.     }
  1818. }
  1819.  
  1820.  
  1821. void save_animation()
  1822. {
  1823.     Mesh      *mesh, *master;
  1824.     Transform *t;
  1825.     Morph     *m;
  1826.     Vector    temp;
  1827.     int       i, j;
  1828.  
  1829.     printf ("\n");
  1830.  
  1831.     for (t = trans_list; t != NULL; t = t->next) {
  1832.      printf ("Transforming object: %s\n", t->name);
  1833.  
  1834.      ani_matrix = &(t->matrix);
  1835.  
  1836.      mesh = LIST_FIND (mesh_list, t->name);
  1837.  
  1838.      if (mesh == NULL) {
  1839.          printf ("Unable to locate mesh object %s\n", t->name);
  1840.          exit(1);
  1841.      }
  1842.  
  1843.      write_mesh (out, mesh);
  1844.     }
  1845.  
  1846.     for (m = morph_list; m != NULL; m = m->next) {
  1847.     printf ("Morphing object: %s\n", m->name);
  1848.  
  1849.     ani_matrix = &(m->matrix);
  1850.  
  1851.     mesh = LIST_FIND (mesh_list, m->name);
  1852.     if (mesh == NULL) {
  1853.         printf ("Unable to locate mesh object %s\n", m->name);
  1854.         exit(1);
  1855.     }
  1856.  
  1857.     /* Make a copy to mess with */
  1858.     master = copy_mesh (mesh);
  1859.     master->hidden = FALSE;
  1860.  
  1861.     strcpy (master->name, m->name);
  1862.  
  1863.     for (i = 0; i < master->vertices; i++)
  1864.         vect_init (master->vertex[i], 0.0, 0.0, 0.0);
  1865.  
  1866.     for (i = 0; i < m->count; i++) {
  1867.         mesh = LIST_FIND (mesh_list, m->names[i]);
  1868.         if (mesh == NULL) {
  1869.         printf ("Unable to locate mesh object %s\n", m->names[0]);
  1870.         exit(1);
  1871.         }
  1872.  
  1873.         if (mesh->vertices != master->vertices)
  1874.         abortmsg ("Morphed objects do not contain the same number of vertices", 1);
  1875.  
  1876.         if (mesh->faces != master->faces)
  1877.         abortmsg ("Morphed objects do not contain the same number of faces", 1);
  1878.  
  1879.         for (j = 0; j < master->vertices; j++) {
  1880.         vect_transform (temp, mesh->vertex[j], mesh->invmatrix);
  1881.         vect_scale (temp, temp, m->weight[i]);
  1882.         vect_add (master->vertex[j], master->vertex[j], temp);
  1883.         }
  1884.     }
  1885.  
  1886.     for (i = 0; i < master->vertices; i++)
  1887.         vect_transform (master->vertex[i], master->vertex[i], master->matrix);
  1888.  
  1889.     write_mesh (out, master);
  1890.  
  1891.     free_mesh_data (master);
  1892.     free (master);
  1893.     }
  1894.  
  1895.     for (mesh = mesh_list; mesh != NULL; mesh = mesh->next)
  1896.     free_mesh_data (mesh);
  1897. }
  1898.  
  1899.  
  1900. /* Create a new mesh */
  1901. Mesh *create_mesh (char *name, int vertices, int faces)
  1902. {
  1903.     Mesh *new_mesh;
  1904.  
  1905.     new_mesh = malloc (sizeof(*new_mesh));
  1906.     if (new_mesh == NULL)
  1907.     abortmsg ("Out of memory allocating mesh", 1);
  1908.  
  1909.     strcpy (new_mesh->name, name);
  1910.  
  1911.     new_mesh->vertices = vertices;
  1912.  
  1913.     if (vertices <= 0)
  1914.     new_mesh->vertex = NULL;
  1915.     else {
  1916.     new_mesh->vertex = malloc (vertices * sizeof(*new_mesh->vertex));
  1917.     if (new_mesh->vertex == NULL)
  1918.         abortmsg ("Out of memory allocating mesh", 1);
  1919.     }
  1920.  
  1921.     new_mesh->faces = faces;
  1922.  
  1923.     if (faces <= 0) {
  1924.     new_mesh->face = NULL;
  1925.     new_mesh->mtl = NULL;
  1926.     }
  1927.     else {
  1928.     new_mesh->face = malloc (faces * sizeof(*new_mesh->face));
  1929.     if (new_mesh->face == NULL)
  1930.         abortmsg ("Out of memory allocating mesh", 1);
  1931.  
  1932.     new_mesh->mtl = malloc (faces * sizeof(*new_mesh->mtl));
  1933.     if (new_mesh->mtl == NULL)
  1934.         abortmsg ("Out of memory allocating mesh", 1);
  1935.     }
  1936.  
  1937.     vect_init (new_mesh->center,  0.0, 0.0, 0.0);
  1938.     vect_init (new_mesh->lengths, 0.0, 0.0, 0.0);
  1939.  
  1940.     mat_identity (new_mesh->matrix);
  1941.     mat_identity (new_mesh->invmatrix);
  1942.  
  1943.     new_mesh->hidden = FALSE;
  1944.     new_mesh->shadow = TRUE;
  1945.  
  1946.     return new_mesh;
  1947. }
  1948.  
  1949.  
  1950. /* Creates a duplicate copy of a mesh */
  1951. Mesh *copy_mesh (Mesh *mesh)
  1952. {
  1953.     Mesh *new_mesh;
  1954.     int  i;
  1955.  
  1956.     new_mesh = create_mesh (mesh->name, mesh->vertices, mesh->faces);
  1957.  
  1958.     if (new_mesh == NULL)
  1959.     abortmsg ("Out of memory allocating mesh", 1);
  1960.  
  1961.     for (i = 0; i < mesh->vertices; i++)
  1962.     vect_copy (new_mesh->vertex[i], mesh->vertex[i]);
  1963.  
  1964.     for (i = 0; i < mesh->faces; i++) {
  1965.     new_mesh->face[i] = mesh->face[i];
  1966.     new_mesh->mtl[i]  = mesh->mtl[i];
  1967.     }
  1968.  
  1969.     mat_copy (new_mesh->matrix, mesh->matrix);
  1970.     mat_copy (new_mesh->invmatrix, mesh->invmatrix);
  1971.  
  1972.     vect_copy (new_mesh->center,  mesh->center);
  1973.     vect_copy (new_mesh->lengths, mesh->lengths);
  1974.  
  1975.     new_mesh->hidden = mesh->hidden;
  1976.     new_mesh->shadow = mesh->shadow;
  1977.  
  1978.     return new_mesh;
  1979. }
  1980.  
  1981.  
  1982. /* Free all data associated with mesh object */
  1983. void free_mesh_data (Mesh *mesh)
  1984. {
  1985.     if (mesh->vertex != NULL)
  1986.     free (mesh->vertex);
  1987.  
  1988.     if (mesh->face != NULL)
  1989.     free (mesh->face);
  1990.  
  1991.     if (mesh->mtl != NULL)
  1992.     free (mesh->mtl);
  1993. }
  1994.  
  1995.  
  1996. /* Updates the center (pivot) point of the mesh */
  1997. void update_limits (Mesh *mesh)
  1998. {
  1999.     Vector vmin = {+MAXFLOAT, +MAXFLOAT, +MAXFLOAT};
  2000.     Vector vmax = {-MAXFLOAT, -MAXFLOAT, -MAXFLOAT};
  2001.     int    i;
  2002.  
  2003.     for (i = 0; i < mesh->vertices; i++) {
  2004.     vect_min (vmin, vmin, mesh->vertex[i]);
  2005.     vect_max (vmax, vmax, mesh->vertex[i]);
  2006.     }
  2007.  
  2008.     vect_add  (mesh->center, vmin, vmax);
  2009.     vect_scale (mesh->center, mesh->center, 0.5);
  2010.  
  2011.     vect_sub (mesh->lengths, vmax, vmin);
  2012. }
  2013.  
  2014.  
  2015. /* Return the sub-string of 'str' that is before 'target' */
  2016. char *before (char *str, char *target)
  2017. {
  2018.     static char result[256];
  2019.     char   *search;
  2020.  
  2021.     strncpy (result, str, 256);
  2022.     result[255] = '\0';
  2023.  
  2024.     search = strstr (result, target);
  2025.  
  2026.     if (search != NULL)
  2027.     *search = '\0';
  2028.  
  2029.     return result;
  2030. }
  2031.  
  2032.  
  2033. /* Return the sub-string of 'str' that is after 'target' */
  2034. char *after (char *str, char *target)
  2035. {
  2036.     static char result[256];
  2037.     char   *search;
  2038.  
  2039.     search = strstr (str, target);
  2040.  
  2041.     if (search == NULL)
  2042.     strncpy (result, "", 256);
  2043.     else
  2044.     strncpy (result, search + strlen(target), 256);
  2045.  
  2046.     result[255] = '\0';
  2047.  
  2048.     return result;
  2049. }
  2050.  
  2051.  
  2052. /* Return the sub-string of 'str' that is between 'target1' and 'target2' */
  2053. char *between (char *str, char *target1, char *target2)
  2054. {
  2055.     static char result[256];
  2056.  
  2057.     strcpy (result, after (str, target1));
  2058.     strcpy (result, before (result, target2));
  2059.  
  2060.     return result;
  2061. }
  2062.  
  2063.  
  2064. /* Works like the C strtok() function except that it can handle */
  2065. /* tokens enclosed in double quotes */
  2066. char *parse_string (char *str)
  2067. {
  2068.     static char result[256];
  2069.     static char *p;
  2070.     char QUOTE = '\"';
  2071.     int  index;
  2072.  
  2073.     strcpy (result, "");
  2074.     index = 0;
  2075.  
  2076.     if (str != NULL)
  2077.     p = str;
  2078.  
  2079.     /* Find the start of the next token */
  2080.     while (isspace (*p))
  2081.     p++;
  2082.  
  2083.     if (*p == QUOTE) {
  2084.     p++;
  2085.  
  2086.     while (*p != '\0' && *p != QUOTE)
  2087.         result[index++] = *p++;
  2088.  
  2089.     if (*p == QUOTE)
  2090.         p++;
  2091.     }
  2092.     else {
  2093.     while (*p != '\0' && !isspace(*p))
  2094.         result[index++] = *p++;
  2095.     }
  2096.  
  2097.     result[index] = '\0';
  2098.  
  2099.     return result;
  2100. }
  2101.  
  2102.  
  2103. /* Convert character 'c' to upper case */
  2104. char upcase (char c)
  2105. {
  2106.     if (c >= 'a' && c <= 'z')
  2107.     c = c - 'a' + 'A';
  2108.  
  2109.     return c;
  2110. }
  2111.  
  2112.  
  2113. float colour_intens (Colour *colour)
  2114. {
  2115.     return sqrt (colour->red   * colour->red +
  2116.          colour->green * colour->green +
  2117.          colour->blue  * colour->blue);
  2118. }
  2119.  
  2120.  
  2121. void parse_file()
  2122. {
  2123.     Chunk chunk;
  2124.  
  2125.     start_chunk(&chunk);
  2126.  
  2127.     if (chunk.tag == 0x4D4D)
  2128.     parse_3ds (&chunk);
  2129.     else
  2130.     abortmsg ("Error: Input file is not .3DS format", 1);
  2131.  
  2132.     end_chunk (&chunk);
  2133. }
  2134.  
  2135.  
  2136. void parse_3ds (Chunk *mainchunk)
  2137. {
  2138.     Chunk chunk;
  2139.  
  2140.     do  {
  2141.     start_chunk (&chunk);
  2142.  
  2143.     if (chunk.end <= mainchunk->end) {
  2144.         switch (chunk.tag) {
  2145.         case 0x3D3D: parse_mdata (&chunk);
  2146.                  break;
  2147.         }
  2148.     }
  2149.  
  2150.     end_chunk (&chunk);
  2151.     } while (chunk.end <= mainchunk->end);
  2152. }
  2153.  
  2154.  
  2155. void parse_mdata (Chunk *mainchunk)
  2156. {
  2157.     Chunk chunk;
  2158.     Colour bgnd_colour;
  2159.  
  2160.     do  {
  2161.     start_chunk (&chunk);
  2162.  
  2163.     if (chunk.end <= mainchunk->end) {
  2164.         switch (chunk.tag) {
  2165.         case 0x2100: parse_colour (&global_amb);
  2166.                  break;
  2167.         case 0x1200: parse_colour (&bgnd_colour);
  2168.                  break;
  2169.         case 0x1201: write_bgsolid (out, bgnd_colour);
  2170.                  break;
  2171.         case 0x2200: parse_fog (&chunk);
  2172.                  break;
  2173.         case 0x2210: parse_fog_bgnd();
  2174.                  break;
  2175.         case 0x2201: write_fog (out, fog_colour, fog_distance);
  2176.                  break;
  2177.         case 0xAFFF: parse_mat_entry (&chunk);
  2178.                  break;
  2179.         case 0x4000: parse_named_object (&chunk);
  2180.                  break;
  2181.         }
  2182.     }
  2183.  
  2184.     end_chunk (&chunk);
  2185.     } while (chunk.end <= mainchunk->end);
  2186. }
  2187.  
  2188.  
  2189. void parse_fog (Chunk *mainchunk)
  2190. {
  2191.     Chunk chunk;
  2192.  
  2193.     (void)read_float();
  2194.     (void)read_float();
  2195.     fog_distance = read_float();
  2196.     (void)read_float();
  2197.  
  2198.     parse_colour (&fog_colour);
  2199.  
  2200.     do  {
  2201.     start_chunk (&chunk);
  2202.  
  2203.     if (chunk.end <= mainchunk->end) {
  2204.         switch (chunk.tag) {
  2205.         case 0x2210: parse_fog_bgnd();
  2206.                  break;
  2207.         }
  2208.     }
  2209.  
  2210.     end_chunk (&chunk);
  2211.     } while (chunk.end <= mainchunk->end);
  2212. }
  2213.  
  2214.  
  2215. void parse_fog_bgnd()
  2216. {
  2217.  
  2218. }
  2219.  
  2220.  
  2221. void parse_mat_entry (Chunk *mainchunk)
  2222. {
  2223.     Chunk chunk;
  2224.     MatProp *mprop;
  2225.  
  2226.     mprop = create_mprop();
  2227.  
  2228.     do  {
  2229.     start_chunk (&chunk);
  2230.  
  2231.     if (chunk.end <= mainchunk->end) {
  2232.         switch (chunk.tag) {
  2233.         case 0xA000: strcpy (mprop->name, read_string());
  2234.                  cleanup_name (mprop->name);
  2235.                  break;
  2236.  
  2237.         case 0xA010: parse_colour (&mprop->ambient);
  2238.                  break;
  2239.  
  2240.         case 0xA020: parse_colour (&mprop->diffuse);
  2241.                  break;
  2242.  
  2243.         case 0xA030: parse_colour (&mprop->specular);
  2244.                  break;
  2245.  
  2246.         case 0xA040: mprop->shininess = 100.0*parse_percentage();
  2247.                  break;
  2248.  
  2249.         case 0xA050: mprop->transparency = parse_percentage();
  2250.                  break;
  2251.  
  2252.         case 0xA080: mprop->self_illum = TRUE;
  2253.                  break;
  2254.  
  2255.         case 0xA220: mprop->reflection = parse_percentage();
  2256.                  (void)parse_mapname (&chunk);
  2257.                  break;
  2258.  
  2259.         case 0xA310: if (mprop->reflection == 0.0)
  2260.                  mprop->reflection = 1.0;
  2261.                  break;
  2262.  
  2263.         case 0xA200: mprop->tex_strength = parse_percentage();
  2264.                  strcpy (mprop->tex_map, parse_mapname (&chunk));
  2265.                  break;
  2266.  
  2267.         case 0xA230: mprop->bump_strength = parse_percentage();
  2268.                  strcpy (mprop->bump_map, parse_mapname (&chunk));
  2269.                  break;
  2270.         }
  2271.     }
  2272.  
  2273.     end_chunk (&chunk);
  2274.     } while (chunk.end <= mainchunk->end);
  2275.  
  2276.     LIST_INSERT (mprop_list, mprop);
  2277. }
  2278.  
  2279.  
  2280. char *parse_mapname (Chunk *mainchunk)
  2281. {
  2282.     static char name[80] = "";
  2283.     Chunk chunk;
  2284.  
  2285.     do  {
  2286.     start_chunk (&chunk);
  2287.  
  2288.     if (chunk.end <= mainchunk->end) {
  2289.         switch (chunk.tag) {
  2290.         case 0xA300: strcpy (name, read_string());
  2291.                  break;
  2292.         }
  2293.     }
  2294.  
  2295.     end_chunk (&chunk);
  2296.     } while (chunk.end <= mainchunk->end);
  2297.  
  2298.     return name;
  2299. }
  2300.  
  2301.  
  2302. void parse_named_object (Chunk *mainchunk)
  2303. {
  2304.     Chunk chunk;
  2305.  
  2306.     strcpy (obj_name, read_string());
  2307.     cleanup_name (obj_name);
  2308.  
  2309.     printf ("Working on: %s\n", obj_name);
  2310.  
  2311.     mesh = NULL;
  2312.  
  2313.     do  {
  2314.     start_chunk (&chunk);
  2315.  
  2316.     if (chunk.end <= mainchunk->end) {
  2317.         switch (chunk.tag) {
  2318.         case 0x4100: parse_n_tri_object (&chunk);
  2319.                  break;
  2320.         case 0x4600: parse_n_direct_light (&chunk);
  2321.                  break;
  2322.         case 0x4700: parse_n_camera();
  2323.                  break;
  2324.         case 0x4010: if (mesh != NULL) mesh->hidden = TRUE;
  2325.                  break;
  2326.         case 0x4012: if (mesh != NULL) mesh->shadow = FALSE;
  2327.                  break;
  2328.         }
  2329.     }
  2330.  
  2331.     end_chunk (&chunk);
  2332.     } while (chunk.end <= mainchunk->end);
  2333.  
  2334.     if (mesh != NULL) {
  2335.     update_limits (mesh);
  2336.  
  2337.     if (frame >= 0)
  2338.         LIST_INSERT (mesh_list, mesh);
  2339.     else {
  2340.         write_mesh (out, mesh);
  2341.  
  2342.         free_mesh_data (mesh);
  2343.         free (mesh);
  2344.     }
  2345.     }
  2346. }
  2347.  
  2348.  
  2349. void parse_n_tri_object (Chunk *mainchunk)
  2350. {
  2351.     Chunk chunk;
  2352.  
  2353.     mesh = create_mesh (obj_name, 0, 0);
  2354.  
  2355.     do  {
  2356.     start_chunk (&chunk);
  2357.  
  2358.     if (chunk.end <= mainchunk->end) {
  2359.         switch (chunk.tag) {
  2360.         case 0x4110: parse_point_array();
  2361.                  break;
  2362.         case 0x4120: parse_face_array (&chunk);
  2363.                  break;
  2364.         case 0x4160: parse_mesh_matrix();
  2365.                  break;
  2366.         }
  2367.     }
  2368.  
  2369.     end_chunk (&chunk);
  2370.     } while (chunk.end <= mainchunk->end);
  2371. }
  2372.  
  2373.  
  2374. void parse_point_array()
  2375. {
  2376.     int i;
  2377.  
  2378.     mesh->vertices = read_word();
  2379.     mesh->vertex = malloc (mesh->vertices * sizeof(*(mesh->vertex)));
  2380.     if (mesh->vertex == NULL)
  2381.     abortmsg ("Out of memory allocating mesh", 1);
  2382.  
  2383.     for (i = 0; i < mesh->vertices; i++)
  2384.     read_point (mesh->vertex[i]);
  2385. }
  2386.  
  2387.  
  2388. void parse_face_array (Chunk *mainchunk)
  2389. {
  2390.     Chunk chunk;
  2391.     int i;
  2392.  
  2393.     mesh->faces = read_word();
  2394.     mesh->face = malloc (mesh->faces * sizeof(*(mesh->face)));
  2395.     if (mesh->face == NULL)
  2396.     abortmsg ("Out of memory allocating mesh", 1);
  2397.  
  2398.     mesh->mtl = malloc (mesh->faces * sizeof(*(mesh->mtl)));
  2399.     if (mesh->mtl == NULL)
  2400.     abortmsg ("Out of memory allocating mesh", 1);
  2401.  
  2402.     for (i = 0; i < mesh->faces; i++) {
  2403.     mesh->face[i].a = read_word();
  2404.     mesh->face[i].b = read_word();
  2405.     mesh->face[i].c = read_word();
  2406.     (void)read_word();
  2407.  
  2408.     mesh->mtl[i] = NULL;
  2409.     }
  2410.  
  2411.     do  {
  2412.     start_chunk (&chunk);
  2413.  
  2414.     if (chunk.end <= mainchunk->end) {
  2415.         switch (chunk.tag) {
  2416.         case 0x4130: parse_msh_mat_group();
  2417.                  break;
  2418.         case 0x4150: parse_smooth_group();
  2419.                  break;
  2420.         }
  2421.     }
  2422.  
  2423.     end_chunk (&chunk);
  2424.     } while (chunk.end <= mainchunk->end);
  2425.  
  2426.     for (i = 0; i < mesh->faces; i++) {
  2427.     if (mesh->mtl[i] == NULL)
  2428.         mesh->mtl[i] = update_materials ("Default", 0);
  2429.     }
  2430. }
  2431.  
  2432.  
  2433. void parse_msh_mat_group()
  2434. {
  2435.     Material *new_mtl;
  2436.     char mtlname[80];
  2437.     int  mtlcnt;
  2438.     int  i, face;
  2439.  
  2440.     strcpy (mtlname, read_string());
  2441.     cleanup_name (mtlname);
  2442.  
  2443.     new_mtl = update_materials (mtlname, 0);
  2444.  
  2445.     mtlcnt = read_word();
  2446.  
  2447.     for (i = 0; i < mtlcnt; i++) {
  2448.     face = read_word();
  2449.     mesh->mtl[face] = new_mtl;
  2450.     }
  2451. }
  2452.  
  2453.  
  2454. void parse_smooth_group()
  2455. {
  2456.  
  2457. }
  2458.  
  2459.  
  2460. void parse_mesh_matrix()
  2461. {
  2462.     int i, j;
  2463.  
  2464.     if (mesh != NULL) {
  2465.     for (i = 0; i < 4; i++) {
  2466.         for (j = 0; j < 3; j++)
  2467.         mesh->matrix[i][j] = read_float();
  2468.     }
  2469.  
  2470.     mat_inv (mesh->invmatrix, mesh->matrix);
  2471.     }
  2472. }
  2473.  
  2474.  
  2475. void parse_n_direct_light (Chunk *mainchunk)
  2476. {
  2477.     Chunk chunk;
  2478.     Spotlight *s;
  2479.     OmniLight *o;
  2480.     int light_off = FALSE;
  2481.     int spot_flag = FALSE;
  2482.  
  2483.     read_point (pos);
  2484.     parse_colour (&col);
  2485.  
  2486.     do  {
  2487.     start_chunk (&chunk);
  2488.  
  2489.     if (chunk.end <= mainchunk->end) {
  2490.         switch (chunk.tag) {
  2491.         case 0x4620: light_off = TRUE;
  2492.                  break;
  2493.         case 0x4610: parse_dl_spotlight();
  2494.                  spot_flag = TRUE;
  2495.                  break;
  2496.         }
  2497.     }
  2498.  
  2499.     end_chunk (&chunk);
  2500.     } while (chunk.end <= mainchunk->end);
  2501.  
  2502.     if (light_off)
  2503.     return;
  2504.  
  2505.     if (!spot_flag) {
  2506.     if (frame >= 0) {
  2507.         o = LIST_FIND (omni_list, obj_name);
  2508.  
  2509.         if (o != NULL) {
  2510.         pos[X] = o->pos[X];
  2511.         pos[Y] = o->pos[Y];
  2512.         pos[Z] = o->pos[Z];
  2513.         col    = o->col;
  2514.         }
  2515.     }
  2516.  
  2517.     write_light (out, obj_name, pos, col);
  2518.     }
  2519.     else {
  2520.     if (frame >= 0) {
  2521.         s = LIST_FIND (spot_list, obj_name);
  2522.  
  2523.         if (s != NULL) {
  2524.         pos[X]    = s->pos[X];
  2525.         pos[Y]    = s->pos[Y];
  2526.         pos[Z]    = s->pos[Z];
  2527.         target[X] = s->target[X];
  2528.         target[Y] = s->target[Y];
  2529.         target[Z] = s->target[Z];
  2530.         col       = s->col;
  2531.         hotspot   = s->hotspot;
  2532.         falloff   = s->falloff;
  2533.         }
  2534.     }
  2535.  
  2536.     if (falloff <= 0.0)
  2537.         falloff = 180.0;
  2538.  
  2539.     if (hotspot <= 0.0)
  2540.         hotspot = 0.7*falloff;
  2541.  
  2542.     write_spot (out, obj_name, pos, target, col, hotspot, falloff);
  2543.     }
  2544. }
  2545.  
  2546.  
  2547. void parse_dl_spotlight()
  2548. {
  2549.     read_point (target);
  2550.  
  2551.     hotspot = read_float();
  2552.     falloff = read_float();
  2553. }
  2554.  
  2555.  
  2556. void parse_n_camera()
  2557. {
  2558.     float  bank;
  2559.     float  lens;
  2560.  
  2561.     read_point (pos);
  2562.     read_point (target);
  2563.     bank = read_float();
  2564.     lens = read_float();
  2565.  
  2566.     if (frame >= 0 && cam_list != NULL) {
  2567.     pos[X]    = cam_list->pos[X];
  2568.     pos[Y]    = cam_list->pos[Y];
  2569.     pos[Z]    = cam_list->pos[Z];
  2570.     target[X] = cam_list->target[X];
  2571.     target[Y] = cam_list->target[Y];
  2572.     target[Z] = cam_list->target[Z];
  2573.     lens      = cam_list->lens;
  2574.     bank      = cam_list->bank;
  2575.     }
  2576.  
  2577.     write_camera (out, obj_name, pos, target, lens, bank);
  2578. }
  2579.  
  2580.  
  2581. void parse_colour (Colour *colour)
  2582. {
  2583.     Chunk chunk;
  2584.     Colour_24 colour_24;
  2585.  
  2586.     start_chunk (&chunk);
  2587.  
  2588.     switch (chunk.tag) {
  2589.     case 0x0010: parse_colour_f (colour);
  2590.              break;
  2591.  
  2592.     case 0x0011: parse_colour_24 (&colour_24);
  2593.              colour->red   = colour_24.red/255.0;
  2594.              colour->green = colour_24.green/255.0;
  2595.              colour->blue  = colour_24.blue/255.0;
  2596.              break;
  2597.  
  2598.     default:     abortmsg ("Error parsing colour", 1);
  2599.     }
  2600.  
  2601.     end_chunk (&chunk);
  2602. }
  2603.  
  2604.  
  2605. void parse_colour_f (Colour *colour)
  2606. {
  2607.     colour->red   = read_float();
  2608.     colour->green = read_float();
  2609.     colour->blue  = read_float();
  2610. }
  2611.  
  2612.  
  2613. void parse_colour_24 (Colour_24 *colour)
  2614. {
  2615.     colour->red   = read_byte();
  2616.     colour->green = read_byte();
  2617.     colour->blue  = read_byte();
  2618. }
  2619.  
  2620.  
  2621. float parse_percentage()
  2622. {
  2623.     Chunk chunk;
  2624.     float percent = 0.0;
  2625.  
  2626.     start_chunk (&chunk);
  2627.  
  2628.     switch (chunk.tag) {
  2629.     case 0x0030: percent = parse_int_percentage()/100.0;
  2630.              break;
  2631.  
  2632.     case 0x0031: percent = parse_float_percentage();
  2633.              break;
  2634.  
  2635.     default:     printf ("WARNING: Error parsing percentage");
  2636.     }
  2637.  
  2638.     end_chunk (&chunk);
  2639.  
  2640.     return percent;
  2641. }
  2642.  
  2643.  
  2644. short parse_int_percentage()
  2645. {
  2646.     word percent = read_word();
  2647.  
  2648.     return percent;
  2649. }
  2650.  
  2651.  
  2652. float parse_float_percentage()
  2653. {
  2654.     float percent = read_float();
  2655.  
  2656.     return percent;
  2657. }
  2658.  
  2659.  
  2660. void start_chunk (Chunk *chunk)
  2661. {
  2662.     chunk->start  = ftell(in);
  2663.     chunk->tag    = read_word();
  2664.     chunk->length = read_dword();
  2665.     chunk->end    = chunk->start + chunk->length;
  2666. }
  2667.  
  2668.  
  2669. void end_chunk (Chunk *chunk)
  2670. {
  2671.     fseek (in, chunk->end, 0);
  2672. }
  2673.  
  2674.  
  2675. byte read_byte()
  2676. {
  2677.     byte data;
  2678.  
  2679.     data = fgetc (in);
  2680.  
  2681.     return data;
  2682. }
  2683.  
  2684.  
  2685. word read_word()
  2686. {
  2687.     word data;
  2688.  
  2689.     fread (&data, 2, 1, in);
  2690.  
  2691.     return data;
  2692. }
  2693.  
  2694.  
  2695. dword read_dword()
  2696. {
  2697.     dword data;
  2698.  
  2699.     fread (&data, 4, 1, in);
  2700.  
  2701.     return data;
  2702. }
  2703.  
  2704.  
  2705. float read_float()
  2706. {
  2707.     float data;
  2708.  
  2709.     fread (&data, 4, 1, in);
  2710.  
  2711.     return data;
  2712. }
  2713.  
  2714.  
  2715. void read_point (Vector v)
  2716. {
  2717.     v[X] = read_float();
  2718.     v[Y] = read_float();
  2719.     v[Z] = read_float();
  2720. }
  2721.  
  2722.  
  2723. char *read_string()
  2724. {
  2725.     static char string[80];
  2726.     int i;
  2727.  
  2728.     for (i = 0; i < 80; i++) {
  2729.     string[i] = read_byte();
  2730.  
  2731.     if (string[i] == '\0')
  2732.         break;
  2733.     }
  2734.  
  2735.     return string;
  2736. }
  2737.  
  2738.  
  2739. float findfov (float lens)
  2740. {
  2741.     static float lens_table[13] =
  2742.          { 15.0, 17.0, 24.0, 35.0, 50.0, 85.0, 100.0, 135.0, 200.0,
  2743.            500.0, 625.0, 800.0, 1000.0 };
  2744.     static float fov_table[13] =
  2745.          { 115.0, 102.0, 84.0, 63.0, 46.0, 28.0, 24.0, 18.0,
  2746.            12.0, 5.0, 4.0, 3.125, 2.5 };
  2747.  
  2748.     float fov, f1, f2, l1, l2;
  2749.     int   i;
  2750.  
  2751.     if (lens < 15.0)
  2752.     lens = 15.0;
  2753.     else if (lens > 1000.0)
  2754.     lens = 1000.0;
  2755.  
  2756.     for (i = 0; i < 13; i++)
  2757.     if (lens < lens_table[i])
  2758.         break;
  2759.  
  2760.     if (i == 13)
  2761.     i = 12;
  2762.     else if (i == 0)
  2763.     i = 1;
  2764.  
  2765.     f1 = fov_table[i-1];
  2766.     f2 = fov_table[i];
  2767.     l1 = lens_table[i-1];
  2768.     l2 = lens_table[i];
  2769.  
  2770.     fov = f1 + (lens - l1) * (f2 - f1) / (l2 - l1);
  2771.  
  2772.     return fov;
  2773. }
  2774.  
  2775.  
  2776.